package com.scs.application.modules.finance.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.flow.FlowContext;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.query.QueryGenerator;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Patient;
import com.scs.application.modules.base.mapper.PatientMapper;
import com.scs.application.modules.dept.entity.OprtUseItem;
import com.scs.application.modules.dept.entity.UseDtl;
import com.scs.application.modules.dept.service.OprtUseItemService;
import com.scs.application.modules.dept.service.UseDtlService;
import com.scs.application.modules.finance.dto.BillItemDTO;
import com.scs.application.modules.finance.dto.SettlementCreateBillParamDTO;
import com.scs.application.modules.finance.dto.SettlementMainDTO;
import com.scs.application.modules.finance.entity.Bill;
import com.scs.application.modules.finance.entity.BillItem;
import com.scs.application.modules.finance.mapper.BillMapper;
import com.scs.application.modules.finance.service.BillItemService;
import com.scs.application.modules.finance.service.BillService;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.wm.entity.WorkOrderItem;
import com.scs.application.modules.wm.enums.WorkOrderType;
import com.scs.application.modules.wm.service.TransferItemService;
import com.scs.application.modules.wm.service.WorkOrderItemService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 */
@Service
@Slf4j
public class BillServiceImpl extends BaseServiceImpl<BillMapper, Bill> implements BillService {

    @Autowired
    private TransferItemService transferItemService;

    @Autowired
    private OprtUseItemService oprtUseItemService;

    @Autowired
    private UseDtlService useDtlService;

    @Autowired
    private BillItemService billItemService;

    @Autowired
    private WorkOrderItemService workOrderItemService;

    @Autowired
    private PatientMapper patientMapper;

    /**
     * 查询本月科室消耗
     */
    @Override
    public List<Bill> findThisMonthDeptUse() {
        Calendar calendar = Calendar.getInstance();
        String beginDate = DateFormatUtils.format(DateUtils.getFirstDayOfMonth(calendar.getTime()),"yyyy-MM-dd 00:00:00");
        List<Bill> bills = getDeptUseByMonth(beginDate);
        if (bills.size() == 0) { //本月没有数据，获取上个月的数据
            calendar.add(Calendar.MONTH, -1);
            beginDate = DateFormatUtils.format(DateUtils.getFirstDayOfMonth(calendar.getTime()),"yyyy-MM-dd 00:00:00");
             bills = getDeptUseByMonth(beginDate);
        }
        return bills;
    }

    private List<Bill> getDeptUseByMonth(String beginDate) {
        return  this.list(new QueryWrapper<Bill>().select("id", "dept_name", "sum(amount) as amount")
                .between("bus_date", beginDate, new Date())
                .eq("flag_dept", "1")
                .groupBy("dept_id")
                .orderByDesc("amount")
                .last("limit 5")
        );
    }

    /**
     * 查询本月耗材品种消耗
     */
    @Override
    public List<BillItemDTO> findThisMonthMaterialUse() {
        Calendar calendar = Calendar.getInstance();
        Date beginDate = DateUtils.parse(DateFormatUtils.format(DateUtils.getFirstDayOfMonth(calendar.getTime()),"yyyy-MM-dd 00:00:00"));
        List<BillItemDTO> billItemDTOS = this.baseMapper.findThisMonthMaterialUse(beginDate);
        if (billItemDTOS.size() == 0) {//如果本月没有数据，获取上个月的
            calendar.add(Calendar.MONTH, -1);
            beginDate = DateUtils.parse(DateFormatUtils.format(DateUtils.getFirstDayOfMonth(calendar.getTime()),"yyyy-MM-dd 00:00:00"));
            billItemDTOS = this.baseMapper.findThisMonthMaterialUse(beginDate);
        }

        return billItemDTOS;
    }

    /**
     * 一物一码月度消耗趋势
     * */
    @Override
    public List<Bill> findThisYearOmocUse() {
        return this.baseMapper.findThisYearOmocUse();
    }

    /**
     * 一物一码月度消耗趋势
     * */
    @Override
    public List<Bill> findThisYearMaterialUse() {
        return this.baseMapper.findThisYearMaterialUse();
    }



    @Override
    public IPage billHighPage(QueryContext context) {
        return this.baseMapper.billHighPage(context.getPage(), context.getWrapper(), context.getParams());
    }

    @Override
    public List<SettlementMainDTO> billHighList(QueryContext context) {
        return this.baseMapper.billHighList( context.getWrapper(), context.getParams());
    }

    @Override
    public IPage billLowPage(QueryContext context) {
        return this.baseMapper.billLowPage(context.getPage(), context.getWrapper(), context.getParams());
    }


    @Override
    public List<SettlementMainDTO> billLowList(QueryContext context) {
        return this.baseMapper.billLowList( context.getWrapper(), context.getParams());
    }

    /**
     * @Description：入账打印
     * @Author wyt
     * @Date 2021/12/6
     * @param itemIdArr 业务明细id数组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResult billPrint(String printType, List<String> itemIdArr,boolean isAll,String queryString) {
        List<SettlementMainDTO> settlementMainDTOList;
        if ("high".equals(printType)) {
            if (isAll) {
                QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(queryString, null);
                settlementMainDTOList = this.baseMapper.billHighList(queryWrapper, null);
            } else {
                settlementMainDTOList = this.baseMapper.billHighList(Wrappers.<SettlementMainDTO>query().in("item_id",itemIdArr ), null);
            }
        }else {
            if (isAll) {
                QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(queryString, null);
                settlementMainDTOList = this.baseMapper.billLowList(Wrappers.<SettlementMainDTO>query(), null);
            } else {
                settlementMainDTOList = this.baseMapper.billLowList(Wrappers.<SettlementMainDTO>query().in("item_id",itemIdArr ), null);
            }
        }
        if (settlementMainDTOList == null || settlementMainDTOList.size() < 1){
            if (isAll) {
                throw new BusinessException("当前没有需要打印的数据");
            }
            throw new BusinessException("打印失败，未找到可操作的数据，请刷新列表重试");
        }

        if (!isAll && itemIdArr.size() != settlementMainDTOList.size() ){
            throw new BusinessException("打印失败，所选中的数量【%s】，与符合条件的数量【%s】不一致，请刷新列表重新选择",itemIdArr.size(),settlementMainDTOList.size() );
        }

        //1、按照记账科室、供应商、一物一码、寄售类型 分组，生成对应的记账单
        Map<String,List<SettlementMainDTO>> groupMap= settlementMainDTOList.stream().collect(
                Collectors.groupingBy(
                        tmp-> tmp.getDeptIdBill() + tmp.getDeptIdExec() + tmp.getSupplierId() + tmp.getFlagOmoc() + tmp.getFlagConsignment()
                )
        );

        //创建记账单的公共参数
        SettlementCreateBillParamDTO createBillParamDTO = new SettlementCreateBillParamDTO();
        createBillParamDTO.setLoginUserCode(UserUtils.currentUser().getCode()).setLoginUserName(UserUtils.currentUser().getName());
        createBillParamDTO.setDateNow(DateUtils.now());
        createBillParamDTO.setLocalDateTimeNow(DateUtils.dateToLocalDateTime(createBillParamDTO.getDateNow()));

        //打印时间及是否打印
        createBillParamDTO.setBillFlagPrint(true).setBillPrintTime(createBillParamDTO.getDateNow());


        List<SettlementMainDTO> mainDTOList;
        Bill bill;
        //批量获取要生成的记账单号
        List<String> busKeyList;
        if (printType.equals("high")){
            busKeyList = serialRuleAdapter.getSerialRuleService().batchGenerateCode(SerialKeys.FINANCE_BILL_HIGH_KEY,groupMap.keySet().size());
        }else{
            busKeyList = serialRuleAdapter.getSerialRuleService().batchGenerateCode(SerialKeys.FINANCE_BILL_LOW_KEY,groupMap.keySet().size());
        }
        int index = 0;
        List<Bill> billListSave = new ArrayList<Bill>();
        List<BillItem> billItemListSave = new ArrayList<BillItem>();
        for(String deptIdBill : groupMap.keySet()) {
            mainDTOList = groupMap.get(deptIdBill);

            //1、记账单主表，直接赋值主键方便后面使用
            createBillParamDTO.setBusKey(busKeyList.get(index)).setIdNew(IdWorker.getIdStr());
            bill=_getBillNew(mainDTOList, createBillParamDTO);
            billListSave.add(bill);

            //2、记账单明细
            billItemListSave.addAll(_getBillItemNew(mainDTOList, bill));
            index++;
        }

        String msg ="入账单生成成功 ";

        //更新关联业务明细表
        msg+=_updateRefBusTables(billItemListSave,false);

        //保存记账明细
        billItemService.saveBatch(billItemListSave);
        msg+= "  <br>新增记账明细数量："+billItemListSave.size();

        //保存记账单
        this.saveBatch(billListSave);

        msg+= "  <br>新增记账单数量："+billListSave.size();
        log.info("billPrint结束：{}",msg);
        return RestResult.ok(msg,billListSave);
    }
    /**
     * @Description：入账打印 添加明细
     * @param itemIdArr 业务明细id数组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String billPrintAddDtl(String printType, List<String> itemIdArr, String billId) {
        List<SettlementMainDTO> settlementMainDTOList;
        if ("high".equals(printType)) {
            settlementMainDTOList = this.baseMapper.billHighList(Wrappers.<SettlementMainDTO>query().in("item_id",itemIdArr ), null);
        }else {
            settlementMainDTOList = this.baseMapper.billLowList(Wrappers.<SettlementMainDTO>query().in("item_id",itemIdArr ), null);
        }
        if (settlementMainDTOList == null || settlementMainDTOList.size() < 1){
            throw new BusinessException("打印失败，未找到可操作的数据，请刷新列表重试");
        }

        if (itemIdArr.size() != settlementMainDTOList.size() ){
            throw new BusinessException("打印失败，所选中的数量【%s】，与符合条件的数量【%s】不一致，请刷新列表重新选择",itemIdArr.size(),settlementMainDTOList.size() );
        }

        Bill bill = this.baseMapper.selectById(billId);
        if (bill == null) {
            throw new BusinessException("该入账单不存在或者已被删除，请刷新重试");
        }
        if (!GlobalConsts.FLOW_START_VALUE.equals(bill.getFlowStatus())){
            throw new BusinessException("该记账单【%s】流程不是制单状态，不可添加",bill.getBusKey());
        }

        //1、添加记账单明细
        List<BillItem> billItemListSave = new ArrayList<BillItem>();
        billItemListSave.addAll(_getBillItemNew(settlementMainDTOList, bill));

        String msg ="明细添加成功 ";

        //更新关联业务明细表
        msg+=_updateRefBusTables(billItemListSave,false);

        //保存记账明细
        billItemService.saveBatch(billItemListSave);
        msg+= "  <br>新增记账明细数量："+billItemListSave.size();

        //更新记账单
        List<BillItem> billItemListAll = billItemService.list(Wrappers.<BillItem>query().eq("bill_id",bill.getId()));
        bill.setAmount(
                billItemListAll.stream().mapToDouble(BillItem::getAmount).sum()
        );

        bill.setBusDateCycle(_getBusDateCycle(
                billItemListAll.stream().filter(tmp -> tmp.getRefBusDate() != null).map(BillItem::getRefBusDate).distinct().collect(Collectors.toList())
        ));
        this.updateById(bill);

        log.info("billPrintAddDtl：{}",msg);
        return msg;
    }


    /**
     * @Description：入账取消打印
     * @Author wyt
     * @Date 2021/12/6
     * @param itemIdArr 业务明细id数组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String billPrintCancel(String[] itemIdArr,List<BillItem> billItemList) {
        if (billItemList == null){
            billItemList = this.billItemService.list(Wrappers.<BillItem>query().in("ref_bus_item_id",itemIdArr));
        }
        if (billItemList == null || billItemList.size() < 1){
            throw new BusinessException("取消打印失败，未找到可操作的数据，请刷新列表重试");
        }

        //取消的时候不做数量判断了，有多少取消多少
        /*if (itemIdArr.length != billItemList.size() ){
            throw new BusinessException("取消打印失败，所选中的数量【%s】，与符合条件的数量【%s】不一致，请刷新列表重新选择",itemIdArr.length,billItemList.size() );
        }*/


        String msg="取消打印成功 ";

        //1、清除业务明细关联关系
        msg+=_updateRefBusTables(billItemList,true);

        //2、删除记账单明细
        List<String> billItemIdList = billItemList.stream().map(BillItem::getId).collect(Collectors.toList());

        billItemService.removeCascadeByIds(billItemIdList);
        msg+= "  <br>删除记账明细数量："+billItemIdList.size();

        //3、更新记账单据金额
        List<String> billIdList = billItemList.stream().map(BillItem::getBillId).distinct().collect(Collectors.toList());
        List<Bill> billList = this.baseMapper.selectList(Wrappers.<Bill>query().in("id", billIdList));
        Map<String,List<BillItem>> billItemListAll = billItemService.list(Wrappers.<BillItem>query().in("bill_id",billIdList)).stream().collect(Collectors.groupingBy(BillItem::getBillId));

        List<Bill> billListUpdate = new ArrayList<Bill>();
        List<String> billIdToNullList = new ArrayList<String>();
        for(Bill bill : billList) {
            if (!GlobalConsts.FLOW_START_VALUE.equals(bill.getFlowStatus())) {
                throw new BusinessException("该记账单【%s】流程不是制单状态，不可取消",bill.getBusKey());
            }
            if (billItemListAll != null && billItemListAll.keySet().size() > 0 && billItemListAll.containsKey(bill.getId())) {
                bill.setAmount(
                        billItemListAll.get(bill.getId()).stream().mapToDouble(BillItem::getAmount).sum()
                );

                bill.setBusDateCycle(_getBusDateCycle(
                        billItemListAll.get(bill.getId()).stream().filter(tmp -> tmp.getRefBusDate() != null).map(BillItem::getRefBusDate).distinct().collect(Collectors.toList())
                ));
                billListUpdate.add(bill);
            }else{
                billIdToNullList.add(bill.getId());
            }
        }

        //更新金额的
        if (billListUpdate.size() > 0) {
            super.updateBatchById(billListUpdate);
        }

        //置空的
        if (billIdToNullList.size() > 0) {
            super.update(Wrappers.<Bill>update().setSql(" bill_print_time=null,bill_flag_print='0',amount=0,bus_date_cycle ='无' ").in("id", billIdToNullList));
        }

        msg+= "  <br>更新记账单数量："+billListUpdate.size()+billIdToNullList.size();

        log.info("billPrint结束：{}",msg);
        return msg;
    }

    /**
    * @Description： 更新记账明细相关业务明细表
    * @param billItemList 记账单明细列表
    * @param isClear    true：清除关系，false:增加关系
    */
    private String _updateRefBusTables(List<BillItem> billItemList,boolean isClear) {
        String msg = "";
        if (isClear) {
            List<String> oprtUseItemIdList = new ArrayList<String>();
            List<String> useItemIdList = new ArrayList<String>();
            List<String> workOrderItemIdList = new ArrayList<String>();
            for(BillItem billItemEach: billItemList) {
                switch (billItemEach.getRefBusItemTable()){
                    case "dept_oprt_use_item":  //病人消耗单明细
                        oprtUseItemIdList.add(billItemEach.getRefBusItemId());
                        break;
                    case "dept_use_dtl":  //科室消耗单明细
                        useItemIdList.add(billItemEach.getRefBusItemId());
                        break;
                    case "wm_work_order_item_in":  //购销入库明细
                        workOrderItemIdList.add(billItemEach.getRefBusItemId());
                        break;
                    case "wm_work_order_item_out":  //购销出库明细
                        workOrderItemIdList.add(billItemEach.getRefBusItemId());
                        break;
                    default:
                        throw  new BusinessException("未实现的业务表【%s】",billItemEach.getRefBusItemTable());
                }
            }

            if (oprtUseItemIdList.size() > 0) {
                oprtUseItemService.update(null,Wrappers.<OprtUseItem>update().setSql(" bill_id=null,bill_item_id=null ").in("id", oprtUseItemIdList));
                msg+= "  <br>更新病人消耗明细数量："+oprtUseItemIdList.size();
            }

            if (useItemIdList.size() > 0) {
                useDtlService.update(null,Wrappers.<UseDtl>update().setSql(" bill_id=null,bill_item_id=null ").in("id", useItemIdList));
                msg+= "  <br>更新科室消耗明细数量："+useItemIdList.size();
            }

            if (workOrderItemIdList.size() > 0) {
                workOrderItemService.update(null,Wrappers.<WorkOrderItem>update().setSql(" bill_id=null,bill_item_id=null ").in("id", workOrderItemIdList));
                msg+= "  <br>更新购销入库明细数量："+workOrderItemIdList.size();
            }
            log.info("_updateRefBusTables结果 {}",msg);
            return msg;
        }


        /**更新业务明细与记账单关联关系  汇总每个记账单明细与业务明细表的更新关系
         * 根据业务明细表分批操作
         */
        List<OprtUseItem> oprtUseItemListUpdate = new ArrayList<OprtUseItem>();
        List<UseDtl> useItemListUpdate = new ArrayList<UseDtl>();
        List<WorkOrderItem> workOrderItemListUpdate = new ArrayList<WorkOrderItem>();
        OprtUseItem oprtUseItem;
        UseDtl useItem;
        WorkOrderItem workOrderItem;
        for(BillItem billItemEach: billItemList) {
            switch (billItemEach.getRefBusItemTable()){
                case "dept_oprt_use_item":  //病人消耗单明细
                    oprtUseItem = new OprtUseItem();
                    oprtUseItem.setBillId(billItemEach.getBillId()).setBillItemId(billItemEach.getId()).setId(billItemEach.getRefBusItemId());
                    oprtUseItemListUpdate.add(oprtUseItem);
                    break;

                case "dept_use_dtl":  //科室消耗单明细
                    useItem = new UseDtl();
                    useItem.setBillId(billItemEach.getBillId()).setBillItemId(billItemEach.getId()).setId(billItemEach.getRefBusItemId());
                    useItemListUpdate.add(useItem);
                    break;
                case "wm_work_order_item_in":  //购销入库
                    workOrderItem = new WorkOrderItem();
                    workOrderItem.setBillId(billItemEach.getBillId()).setBillItemId(billItemEach.getId()).setId(billItemEach.getRefBusItemId());
                    workOrderItemListUpdate.add(workOrderItem);
                    break;
                case "wm_work_order_item_out":  //购销出库
                    workOrderItem = new WorkOrderItem();
                    workOrderItem.setBillId(billItemEach.getBillId()).setBillItemId(billItemEach.getId()).setId(billItemEach.getRefBusItemId());
                    workOrderItemListUpdate.add(workOrderItem);
                    break;

                default:
                    throw  new BusinessException("未实现的业务表【%s】",billItemEach.getRefBusItemTable());
            }
        }
        //一条记账单明细只能关联一条业务明细，所以需要保存的记账明细有多少，就需要更新多少对应的关系
        if (billItemList.size() != oprtUseItemListUpdate.size() + useItemListUpdate.size() + workOrderItemListUpdate.size()  ) {
            throw  new BusinessException("更新业务明细失败，记账明细数量【%s】，业务明细数量【%s】，请刷新列表重新选择",billItemList.size(),(oprtUseItemListUpdate.size() + useItemListUpdate.size()));
        }

        //更新病人消耗单明细
        List<String> busItemIdList,billItemIdList;
        int countUpdate = 0;
        if (oprtUseItemListUpdate.size() > 0) {
            oprtUseItemService.updateBatchById(oprtUseItemListUpdate);
            //校验下更新数量
            busItemIdList = oprtUseItemListUpdate.stream().map(OprtUseItem::getId).collect(Collectors.toList());
            billItemIdList = oprtUseItemListUpdate.stream().map(OprtUseItem::getBillItemId).collect(Collectors.toList());
            countUpdate = oprtUseItemService.count(Wrappers.<OprtUseItem>query().in("id",busItemIdList).in("bill_item_id",billItemIdList));
            if (oprtUseItemListUpdate.size() != countUpdate ){
                throw  new BusinessException("更新病人消耗明细失败，关联记账明细数量【%s】，业务明细更新数量【%s】，请刷新列表重新选择",oprtUseItemListUpdate.size(),countUpdate);
            }
            msg+= "  <br>更新病人消耗明细数量："+countUpdate;
        }

        //更新科室消耗单明细
        if (useItemListUpdate.size() > 0) {
            useDtlService.updateBatchById(useItemListUpdate);
            //校验下更新数量
            busItemIdList = useItemListUpdate.stream().map(UseDtl::getId).collect(Collectors.toList());
            billItemIdList = useItemListUpdate.stream().map(UseDtl::getBillItemId).collect(Collectors.toList());
            countUpdate = useDtlService.count(Wrappers.<UseDtl>query().in("id",busItemIdList).in("bill_item_id",billItemIdList));
            if (useItemListUpdate.size() != countUpdate ){
                throw  new BusinessException("更新科室消耗单明细失败，关联记账明细数量【%s】，业务明细更新数量【%s】，请刷新列表重新选择",useItemListUpdate.size(),countUpdate);
            }
            msg+= "  <br>更新科室消耗单明细数量："+countUpdate;
        }

        //更新购销入库明细
        if (workOrderItemListUpdate.size() > 0) {
            workOrderItemService.updateBatchById(workOrderItemListUpdate);
            //校验下更新数量
            busItemIdList = workOrderItemListUpdate.stream().map(WorkOrderItem::getId).collect(Collectors.toList());
            billItemIdList = workOrderItemListUpdate.stream().map(WorkOrderItem::getBillItemId).collect(Collectors.toList());
            countUpdate = workOrderItemService.count(Wrappers.<WorkOrderItem>query().in("id",busItemIdList).in("bill_item_id",billItemIdList));
            if (workOrderItemListUpdate.size() != countUpdate ){
                throw  new BusinessException("更新购销入库明细失败，关联记账明细数量【%s】，业务明细更新数量【%s】，请刷新列表重新选择",workOrderItemListUpdate.size(),countUpdate);
            }
            msg+= "  <br>更新购销入库明细数量："+countUpdate;
        }
        log.info("_updateRefBusTables结果 {}",msg);
        return msg;
    }

    /**
     * 获取需要创建的记账单
     * @param list    分组列表
     * @param createBillParamDTO 创建参数
     * @return
     */
    private Bill _getBillNew(List<SettlementMainDTO> list,SettlementCreateBillParamDTO createBillParamDTO) {
        SettlementMainDTO groupOne = list.get(0);
        String msgPre=String.format("记账单创建校验失败！<br>业务单据：%s<br>记账科室：%s<br>业务明细id：%s<br>",groupOne.getBusKey(),StringUtils.defaultString(groupOne.getDeptNameBill(),"无科室"),groupOne.getItemId());

        //一些必要的判断
        if (groupOne.getFlagConsignment() == null) {
            throw  new BusinessException( msgPre+"%s","寄售类型为非法数据(为null)");
        }
        if (groupOne.getFlagOmoc() == null) {
            throw  new BusinessException( msgPre+"%s","一物一码类型为非法数据(为null)");
        }
        if (groupOne.getFlagRed() == null) {
            throw  new BusinessException( msgPre+"%s","冲红类型为非法数据(为null)");
        }

        //非购销入库的时候，才判断记账科室
        if (!"购销入库".equals(groupOne.getBusTypeName()) && !"购销供应商出库".equals(groupOne.getBusTypeName())) {
            if (StringUtils.isAllBlank(groupOne.getDeptIdBill())) {
                throw  new BusinessException( msgPre+"%s","记账科室id为null");
            }
            if (StringUtils.isAllBlank(groupOne.getDeptNameBill())) {
                throw  new BusinessException( msgPre+"%s","记账科室名称为null");
            }
            Dept dept = (Dept) CacheUtils.get(CacheUtils.BASE_DEPT, groupOne.getDeptIdBill());
            if (dept == null) {
                throw  new BusinessException( msgPre+"%s","记账科室不存在或者已被删除");
            }
            if (dept.getFlagBus() != null &&  !dept.getFlagBus()) {
                throw  new BusinessException( msgPre+"%s","非业务科室，不可以进行业务操作");
            }
        }
        if (StringUtils.isAllBlank(groupOne.getSupplierId())) {
            throw  new BusinessException( msgPre+"%s","供应商id为空");
        }
        if (StringUtils.isAllBlank(groupOne.getSupplierName())) {
            throw  new BusinessException( msgPre+"%s","供应商名称为空");
        }
        msgPre = null;

        Bill bill = new Bill();
        bill.setId(createBillParamDTO.getIdNew());
        bill.setBusKey(createBillParamDTO.getBusKey());
        bill.setBusDate(createBillParamDTO.getDateNow());
        bill.setBusUser(createBillParamDTO.getLoginUserName());
        bill.setSupplierId(groupOne.getSupplierId());
        bill.setSupplierName(groupOne.getSupplierName());
        bill.setDeptId(groupOne.getDeptIdBill());
        bill.setDeptName(groupOne.getDeptNameBill());
        bill.setExecDeptId(groupOne.getDeptIdExec());
        bill.setExecDeptName(groupOne.getDeptNameExec());
        bill.setFlagConsignment(groupOne.getFlagConsignment());
        bill.setFlagOmoc(groupOne.getFlagOmoc());


        if ("购销入库".equals(groupOne.getBusTypeName()) || "购销供应商出库".equals(groupOne.getBusTypeName())) {  //购销入库
            bill.setFlagDept(false);
            bill.setFlagSupplier(false);
        }else { //非购销入库
            bill.setFlagDept(true);
            //供应商记账单 是代销并且不是期初供应商
            bill.setFlagSupplier(bill.getFlagConsignment() && !GlobalConsts.Spd.supplierNameInit.equals(bill.getSupplierName()));
        }

        if (createBillParamDTO.getBillPrintTime() != null) {
            bill.setBillPrintTime(createBillParamDTO.getBillPrintTime());
        }
        if (createBillParamDTO.getBillFlagPrint() != null) {
            bill.setBillFlagPrint(createBillParamDTO.getBillFlagPrint());
        }

        //流程修改人、流程修改人代码、流程修改时间
        bill.setFlowModifier(createBillParamDTO.getLoginUserName());
        bill.setFlowModifierCode(createBillParamDTO.getLoginUserCode());
        bill.setFlowModified(createBillParamDTO.getLocalDateTimeNow());

        //备注
        bill.setBusDateCycle(_getBusDateCycle(
                list.stream().map(SettlementMainDTO::getBusDate).collect(Collectors.toList())
        ));

        //合计金额
        final double[] amount = {0d};
        list.forEach(tmp -> {
            if (tmp.getFlagRed()) { //冲红 减
                amount[0] = UtilNum.sub(amount[0],Math.abs(tmp.getAmount()));
            }else {//非冲红加
                amount[0] = UtilNum.sum(amount[0],Math.abs(tmp.getAmount()));
            }
        });
        bill.setAmount(amount[0]);
        return bill;
    }

    //获取记账单消耗周期
    private String _getBusDateCycle(List<Date> busDateList) {
        busDateList.sort(new Comparator<Date>() {
            @Override
            public int compare(Date left, Date right) {
                return left.compareTo(right);
            }
        });
        return String.format("%s--%s",
                DateUtils.format(busDateList.get(0),"yyyy-MM-dd"),
                DateUtils.format(busDateList.get(busDateList.size() - 1),"yyyy-MM-dd")
        );
    }

    /**
     * 获取需要创建的记账单明细列表
     * @param list      分组列表
     * @param bill      记账单
     * @return
     */
    private List<BillItem> _getBillItemNew(List<SettlementMainDTO> list,Bill bill) {
        List<BillItem> billItems = new ArrayList<>();

        List<String> mainIdList = list.stream().map(SettlementMainDTO::getMainId).distinct().collect(Collectors.toList());
        //校验旧的数据
        int count = this.count(Wrappers.<Bill>query().in("ifnull(ref_bus_id,'')",mainIdList));
        if (count > 0) {
            throw  new BusinessException("该分组下有业务明细为历史数据产生的记账单，清请先修复数据，之后再进行入账");
        }


        //病人信息
        List<String> patientIdList = list.stream().filter(ob -> StringUtils.isNotBlank(ob.getPatientId())).map(SettlementMainDTO::getPatientId).distinct().collect(Collectors.toList());
        Map<String,Patient> patientIdMap = null;
        if(patientIdList!=null&&patientIdList.size()>0){
            List<Patient> patientList = patientMapper.selectList(Wrappers.<Patient>query().in("id",patientIdList));
            if (patientList != null && patientList.size() > 0) {
                patientIdMap = patientList.stream().collect(Collectors.toMap(Patient::getId, Function.identity()));
                patientList = null;
            }
        }

        for (SettlementMainDTO mainDTO : list) {
            BillItem billItem = new BillItem();
            BeanUtils.copyProperties(mainDTO, billItem);
            billItem.setHisCode(mainDTO.getMatrHisCode()).setHrpCode(mainDTO.getMatrHrpCode());
            billItem.setHisPrice(mainDTO.getMatrHisPrice());


            billItem.setId(IdWorker.getIdStr());
            billItem.setBillId(bill.getId());

            //冲红为负数，非冲红为正数
            billItem.setSkuQty(Math.abs(mainDTO.getSkuQty()) *  (mainDTO.getFlagRed() ? -1 : 1));
            billItem.setAmount(Math.abs(mainDTO.getAmount()) * (mainDTO.getFlagRed() ? -1 : 1));
            billItem.setManufactureName(mainDTO.getMfgName());
            billItem.setCertificateNo(mainDTO.getCertificateNo());

            //是否期初
            billItem.setFlagInit(GlobalConsts.Spd.supplierNameInit.equals(bill.getSupplierName()));

            //主表关联关系
            billItem.setRefBusTable(mainDTO.getBusTable()).setRefBusId(mainDTO.getMainId())
                    .setRefBusKey(mainDTO.getBusKey()).setRefBusType(mainDTO.getBusType()).setRefBusTypeName(mainDTO.getBusTypeName()).setRefBusDate(mainDTO.getBusDate())

                    //明细表关联关系
                    .setRefBusItemTable(mainDTO.getBusItemTable()).setRefBusItemId(mainDTO.getItemId())
                    ;
            //来源业务类型与WorkOrderType保持一致
            if ("购销入库".equals(mainDTO.getBusTypeName())) {  //购销入库
                billItem.setRefBusType(WorkOrderType.IN_MANUAL).setRefBusTypeName("购销入库");
            }else if ("购销供应商出库".equals(mainDTO.getBusTypeName())){ //购销供应商出库
                billItem.setRefBusType(WorkOrderType.OUT_SP).setRefBusTypeName("购销供应商出库");
            }else if ("病人消耗单".equals(mainDTO.getBusTypeName()) && billItem.getFlagRed()){ //病人消耗单冲红
                billItem.setRefBusType(WorkOrderType.IN_OPRT_RED).setRefBusTypeName("病人消耗单冲红");
            }else if ("病人消耗单".equals(mainDTO.getBusTypeName()) && !billItem.getFlagRed()){ //病人消耗单非冲红
                billItem.setRefBusType(WorkOrderType.OPRT_USE).setRefBusTypeName("病人消耗单");
            }else if ("科室消耗单".equals(mainDTO.getBusTypeName()) && billItem.getFlagRed()){ //科室消耗单冲红
                billItem.setRefBusType(WorkOrderType.IN_USE_RED).setRefBusTypeName("科室消耗单冲红");
            }else if ("科室消耗单".equals(mainDTO.getBusTypeName()) && !billItem.getFlagRed()){ //科室消耗单非冲红
                billItem.setRefBusType(WorkOrderType.OUT_USE).setRefBusTypeName("科室消耗单");
            } else {
                BusinessException.throwError("未知业务类型，%s",mainDTO.getBusTypeName());
            }

            if (patientIdMap != null && StringUtils.isNotBlank(mainDTO.getPatientId()) && patientIdMap.containsKey(mainDTO.getPatientId())) {
                billItem.setPatientType(patientIdMap.get(mainDTO.getPatientId()).getType());
            }
            billItems.add(billItem);
        }
        return billItems;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    protected void afterHandleFlowChange(FlowContext flowContext, Bill entity) {
        super.afterHandleFlowChange(flowContext, entity);
        String buttonKey = flowContext.getButtonKey();
        switch (buttonKey){
            case "cancelprint": //取消打印
                flowContext.setHandledMsg(
                        this.billPrintCancel(
                                null,
                                billItemService.list(Wrappers.<BillItem>query().eq("bill_id",entity.getId()))
                        )
                );
                break;
        }
    }

}
